# 导入相关包
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

from Main.main1 import df
from Main.main2 import churn

## 四、用户特征相关性分析
# 计算特征的相关系数矩阵
features = df[['Tenure', 'WarehouseToHome', 'AgeGroup', 'Gender', 'HourSpendOnApp', 'OrderCount',
               'OrderAmountHikeFromlastYear', 'DaySinceLastOrder', 'CouponUsed',
               'NumberOfStreamerFollowed', 'SatisfactionScore', 'DiscountAmount']]
target = df['Churn']

correlation_coefficients = features.corrwith(churn)
print("用户流失相关系数: ")
print(correlation_coefficients)

# 绘制相关系数矩阵图
correlation_matrix = features.corr()

plt.figure(figsize=(10, 6))
sns.heatmap(correlation_matrix, cmap='viridis')
plt.title('Correlation Matrix')
plt.show()

# 结论：
''' 
 Tenure（任期）与用户流失呈负相关，相关系数为 -0.315941。这表明任期较长的用户可能更不容易流失。
 WarehouseToHome与用户流失有一定的正相关性，系数为 0.069544。
 AgeGroup与用户流失呈正相关，说明不同年龄组可能对流失有一定影响。
 Gender与用户流失的相关性较小，为 0.029264。
 HourSpendOnApp与用户流失的相关性也较小，为 0.018126。
 OrderCount与用户流失呈负相关，但相关性较弱，为 -0.015327。
 OrderAmountHikeFromlastYear与用户流失呈负相关。
 DaySinceLastOrder与用户流失呈较强的负相关，这意味着距离上次订单的时间越长，用户越容易流失。
 CouponUsed与用户流失的相关性较弱，为 -0.001430。
 NumberOfStreamerFollowed与用户流失呈正相关。
 SatisfactionScore与用户流失呈正相关，说明用户满意度可能对流失有一定影响。
 DiscountAmount与用户流失呈较强的负相关。
'''

## 五、模型建立与优化
# 导入相关包
from sklearn.ensemble import AdaBoostClassifier, GradientBoostingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn import metrics
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
import lightgbm as lgb
from xgboost.sklearn import XGBClassifier

# 1、模型建立与模型评估
# 1）样本处理
features = df[['Tenure', 'WarehouseToHome', 'AgeGroup', 'Gender', 'HourSpendOnApp', 'OrderCount',
               'OrderAmountHikeFromlastYear', 'DaySinceLastOrder', 'CouponUsed',
               'NumberOfStreamerFollowed', 'SatisfactionScore', 'DiscountAmount']]
target = df['Churn']
target.value_counts()
# 可以看出样本明显不均衡，差别很大

# 过抽样处理样本不均衡问题
from imblearn.over_sampling import SMOTE

oversample = SMOTE(random_state=0)
X, y = oversample.fit_resample(features, target)
y.value_counts()

# 2）建立训练数据集和测试数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

print('过抽样数据特征：', X.shape, '训练数据特征：', X_train.shape, '测试数据特征：', X_test.shape)

print('过抽样后数据标签：', y.shape, '训练数据标签：', y_train.shape, '测试数据标签：', y_test.shape)

# 3)选择机器学习算法训练模型
# 定义机器学习模型
models = [
    ['Logistic Regression', LogisticRegression()],  # 单模型
    ['DecisionTree', DecisionTreeClassifier(criterion='entropy', random_state=0)],
    ['Naive Bayes', GaussianNB()],
    ['K Nearest Neighbors', KNeighborsClassifier(n_neighbors=5)],
    ['Random Forest', RandomForestClassifier()],  # 双模型
    ['AdaBoost', AdaBoostClassifier()],
    ['GBDT', GradientBoostingClassifier()],
    ['LightGBM', lgb.LGBMClassifier()],
    ['XGB', XGBClassifier(eval_metric=['logloss', 'auc', 'error'])]
]

# 作出ROC曲线
Classify_result = []
names = []
prediction = []
for name, model in models:
    model = model
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    accuracy_score = metrics.accuracy_score(y_test, y_pred)
    precision_score = metrics.precision_score(y_test, y_pred)
    recall_score = metrics.recall_score(y_test, y_pred)
    fpr, tpr, _ = metrics.roc_curve(y_test, model.predict_proba(X_test)[:, 1])
    roc_auc = metrics.auc(fpr, tpr)

    # 绘制 ROC 曲线
    plt.figure()
    plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'{name} (area = {roc_auc:.2f})')
    plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.05])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('Receiver Operating Characteristic Curve')
    plt.legend(loc="lower right")
    plt.show()

    class_eva = pd.DataFrame([accuracy_score, precision_score, recall_score, roc_auc])
    Classify_result.append(class_eva)
    name = pd.Series(name)
    names.append(name)
    y_pred = pd.Series(y_pred)
    prediction.append(y_pred)

# 创建参数表格
names = pd.DataFrame(names)
names = names[0].tolist()
result = pd.concat(Classify_result, axis=1)
result.columns = names
result.index = ["accuracy_score", "precision_score", "recall_score", "roc_auc"]
result
# 由图可得：XGBoost算法的学习效果最好，ROC得分为0.995。因此我们选用此模型作为客户流失的预测模型，用于评估是否存在用户流失情况。
# 从整体上看，融合的多模型ROC得分比单模型算法高，学习效果比单模型好。


# 2、模型优化
# 选择学习效果最好的XGB模型，通过GridSearch网格搜索，找到其最优的模型参数
from sklearn.model_selection import GridSearchCV

params = {"learning_rate": [0.01, 0.05, 0.1, 0.2], "n_estimators": [100, 200, 300], "max_depth": [5, 10, 15]}
gridxgbc = GridSearchCV(
    estimator=XGBClassifier(learning_rate=0.1, n_estimators=300, gamma=0, subsample=0.8, colsample_bytree=0.8,
                            nthread=1, scale_pos_weight=1, eval_metric='logloss', seed=27), param_grid=params, cv=5)
gridxgbc.fit(X_train, y_train)

# 打印最优参数和最优分数
print("Best parameters found: ", gridxgbc.best_params_)
print("Best score: {:.4f}".format(gridxgbc.best_score_))  # 0.9760
# 得到最优参数模型为：{'learning_rate': 0.1, 'max_depth': 10, 'n_estimators': 300}
# 即XGBoost模型中弱分类器的数量为300，最大树深度为10，最小叶子节点样本权重和为1

# 使用最优的模型参数，建立XGBoost模型，计算器ROC得分，并输出最优模型参数下的特征及特征重要度。
classifier = XGBClassifier(learning_rate=0.1, min_child_weight=1,
                           max_depth=10, n_estimators=300, gamma=0.4, subsample=0.9, colsample_bytree=0.6, nthread=1,
                           scale_pos_weight=1, eval_metric='logloss', seed=27)
classifier.fit(X_train, y_train)
y_pred = classifier.predict(X_test)
recall = metrics.recall_score(y_test, y_pred)
precision = metrics.precision_score(y_test, y_pred)
roc_score = roc_auc_score(y_test, y_pred)
print("ROC 得分:", roc_score)  # 0.972

# 查看调参后
recall, precision
# 调参后XGBoost模型的精确率为97.1%、召回率为97.2%。

# 查看重要特征
from xgboost import plot_importance

plot_importance(classifier, height=0.5)
plt.show()
# 根据参数调优的XGB模型，对用户流失影响最大的用户特征依次为：上月平均折扣金额、仓库到顾客地址的距离、订单金额同比增长。
# 上述的用户行为特征与相关系数分析的略有差异，整体来说与探索性分析结果基本一致。

'''
建议：
用户方面：针对老年用户、无亲属、无伴侣用户的特征推出定制服务如老年朋友套餐、温暖套餐等。鼓励用户加强关联，推出各种亲子套餐、情侣套餐等，满足客户的多样化需求。针对新注册用户，推送半年优惠如赠送消费券，以度过用户流失高峰期。
优化折扣策略：可以评估和优化折扣策略，确保其既能吸引用户，又不会对企业利润造成过大影响。可适当开展补贴活动，鼓励商家对消费者进行补贴。
考虑距离因素：仓库到顾客地址的距离可能影响用户的满意度和忠诚度。可以优化物流配送策略，减少运输时间和成本，提高用户体验；增加发货仓库，降低商品的运输时间。
关注订单金额增长：对于订单金额同比增长，可以进一步分析增长的原因，并制定相应的营销策略来促进增长。
了解流媒体关注度的影响：探索如何利用用户关注的流媒体数量来提高用户参与度和留存率。
鼓励更多主播创造更多优质直播内容，鼓励用户收藏喜欢的主播，鼓励用户成为主播；
适当开展签到、每日任务等活动，提高用户使用平台时间，增强用户粘性；
对于长时间未下单的用户，平台对其进行精准消息推送，尝试召回用户。
'''
